--- ========================================================= ---
---  Setup Revision, Version, Date and add to AceLibrary
--- ========================================================= ---
local VERSION = tonumber(("$Revision: 52619 $"):match("%d+"))

local DaHud = DaHud
DaHud_Module_Layout = DaHud:NewModule("Module_Layout", "AceEvent-2.0")
local self = DaHud_Layout
if DaHud.revision < VERSION then
	DaHud.version = "r" .. VERSION
	DaHud.revision = VERSION
	DaHud.date = ("$Date: 2007-10-19 21:07:04 -0400 (Fri, 19 Oct 2007) $"):match("%d%d%d%d%-%d%d%-%d%d")
end
DaHud.desc = "Layout Module"

--- ========================================================= ---
---  Setup Locals
--- ========================================================= ---
local L = DaHud:L("DaHud_Module_Layout")

--- ========================================================= ---
---  On Intitalize / Setup Database
--- ========================================================= ---
function DaHud_Module_Layout:OnInitialize()
	self.db = DaHud:AcquireDBNamespace("Module_Layout")
	DaHud:RegisterDefaults("Module_Layout", "profile", {
		settings = {
		},
	})
end

--- ========================================================= ---
---  On Enable
--- ========================================================= ---
function DaHud_Module_Layout:OnEnable()
	self:SetupOptions()
end

--- ========================================================= ---
---  On Disable
--- ========================================================= ---
function DaHud_Module_Layout:OnDisable()
	self:UnregisterAllEvents();
end

--- ========================================================= ---
---  Setup Validates for Options
--- ========================================================= ---
function DaHud_Module_Layout:getLayoutValidate()
	local layoutValidates = {}
	local layouts = DaHud.db.account.customLayouts
	
	local t = {}
	local u = {}
	
	if layouts then
		for k, v in pairs(layouts) do
			t[k] = L[k]
			u[k] = v
		end
	end
	return t
end

function validateLayoutName(value)
	if value == "Default" then
		return false
	end
	if value == "Detailed" then
		return false
	end
	if value == "" then
		return false
	end

	return true
end

function validateSaveLayoutName(value)
	if value == "Default" then
		return false
	end
	if value == "Detailed" then
		return false
	end
	if value == "Custom" then
		return false
	end
	if value == "" then
		return false
	end

	return true
end

--- ========================================================= ---
---  Setup Options
--- ========================================================= ---
function DaHud_Module_Layout:SetupOptions()
	DaHud.options.args.layout = {
		name = L["Layout"],
		desc = L["Layout Options."],
		type = 'group',
		args = {
			import = {
				name = L["Import"],
				desc = L["Import Layout."],
				type = 'execute',
				func = "OpenImportFrame",
				handler = DaHud_Module_Layout,
			},
			export = {
				name = L["Export"],
				desc = L["Export Layout."],
				type = 'text',
				validate = self:getLayoutValidate(frame),
				validateDesc = self:getLayoutValidate(frame),
				get = false,
				set = "OpenExportFrame",
				handler = DaHud_Module_Layout,
			},
			save = {
				name = L["Save"],
				desc = L["Save Layout."],
				type = 'text',
				validate = validateSaveLayoutName,
				get = false,
				set = "SaveLayout",
				handler = DaHud_Module_Layout,
				usage = "<Layout Name>",
			},
			delete = {
				name = L["Delete"],
				desc = L["Delete Layout."],
				type = 'text',
				validate = self:getLayoutValidate(frame),
				validateDesc = self:getLayoutValidate(frame),
				get = false,
				set = "DeleteLayout",
				handler = DaHud_Module_Layout,
			},
			apply = {
				name = L["Apply"],
				desc = L["Apply Layout."],
				type = 'text',
				validate = self:getLayoutValidate(frame),
				validateDesc = self:getLayoutValidate(frame),
				get = false,
				set = "ApplyLayout",
				handler = DaHud_Module_Layout,
			},
		},
	}
end

--- ========================================================= ---
---  Local Functions
--- ========================================================= ---
local new, del
do
	local list = setmetatable({}, {__mode='k'})
	function new(...)
		recycle_num = recycle_num + 1
		local t = next(list)
		if t then
			list[t] = nil
			for i = 1, select('#', ...) do
				t[i] = select(i, ...)
			end
			return t
		else
			return { ... }
		end
	end
	function del(t)
		recycle_num = recycle_num - 1
		for k in pairs(t) do
			t[k] = nil
		end
		t[''] = true
		t[''] = nil
		list[t] = true
		return nil
	end
end

local function escapeChar(c)
    return ("\\%03d"):format(c:byte())
end

local function specialSort(alpha, bravo)
	if alpha == nil or bravo == nil then
		return false
	end
	local type_alpha, type_bravo = type(alpha), type(bravo)
	if type_alpha ~= type_bravo then
		return type_alpha < type_bravo
	end
	if type_alpha == "string" then
		return alpha:lower() < bravo:lower()
	elseif type_alpha == "number" then
		return alpha < bravo
	elseif type_alpha == "table" then
		return #alpha < #bravo
	elseif type_alpha == "boolean" then
		return not alpha
	else
		return false
	end
end

local tab = "    "

local getkeystring
local function toLiteralString(value, depth, t)
	if type(value) == "string" then
		local s = ("%q"):format((value:gsub("|", "||"))):gsub("[\001-\012\014-\031\128-\255]", escapeChar)
		if t then
			t[#t+1] = s
			return
		else
			return s
		end
	elseif type(value) ~= "table" then
		local s = tostring(value)
		if t then
			t[#t+1] = s
			return
		else
			return s
		end
	end
	if next(value) == nil then
		local s = "{}"
		if t then
			t[#t+1] = s
			return
		else
			return s
		end
	end
	if not depth then
		depth = 0
	end
	
	local madeT = not t
	if madeT then
		t = new()
	end
	t[#t+1] = "{\n"
	
	local tmp = new()
	for k in pairs(value) do
		if depth > 0 or (k ~= "Name" and k ~= "Revision") then
			tmp[#tmp+1] = k
		end
	end
	table.sort(tmp, specialSort)
	if depth == 0 then
		table.insert(tmp, 1, "Name")
		table.insert(tmp, 2, "Revision")
	end
	for i,k in ipairs(tmp) do
		tmp[i] = nil
		local v = value[k]
		for i = 1, depth+1 do
			t[#t+1] = tab
		end
		getkeystring(k, depth+1, t)
		t[#t+1] = " = "
		toLiteralString(v, depth+1, t)
		if tmp[i+1] == nil then
			t[#t+1] = "\n"
		else
			t[#t+1] = ",\n"
		end
	end
	tmp = del(tmp)
	
	for i = 1, depth do
		t[#t+1] = tab
	end
	t[#t+1] = "}"
	if madeT then
		local s = table.concat(t)
		t = del(t)
		return s
	end
	return
end

function getkeystring(value, depth, t)
	if type(value) == "string" then
		if value:find("^[%a_][%a%d_]*$") then
			t[#t+1] = value
			return
		end
	end
	t[#t+1] = "["
	toLiteralString(value, depth, t)
	t[#t+1] = "]"
end

local function createDaHudExportFrame()
	DaHudExportFrame = CreateFrame("Frame", "DaHud_ExportFrame", UIParent, "DialogBoxFrame")

	DaHudExportFrame:SetWidth(500)
	DaHudExportFrame:SetHeight(400)
	DaHudExportFrame:SetPoint("CENTER")
	DaHudExportFrame:SetBackdrop({
		bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]], 
	    edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], 
	    tile = true, tileSize = 16, edgeSize = 16, 
	    insets = { left = 5, right = 5, top = 5, bottom = 5 }
	})
	DaHudExportFrame:SetBackdropColor(0,0,0,1)

	local text = DaHudExportFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
	DaHudExportFrame.text = text
	text:SetPoint("TOP", 0, -5)
	text:SetPoint("LEFT")
	
	local closeButton = CreateFrame("Button", "DaHud_ExportFrameCloseButton", DaHudExportFrame, "UIPanelCloseButton")
	closeButton:SetPoint("TOPRIGHT", 0, 0)
	closeButton:SetScript("OnClick", function()
		DaHudExportFrame:Hide()
	end)
	text:SetPoint("RIGHT", closeButton)
	
	local scrollFrame = CreateFrame("ScrollFrame", "DaHud_ExportFrameScrollFrame", DaHudExportFrame, "UIPanelScrollFrameTemplate")
	scrollFrame:SetToplevel(true)
	scrollFrame:SetPoint("TOP", -10, -30)
	scrollFrame:SetWidth(455)
	scrollFrame:SetHeight(330)

	local editBox = CreateFrame("EditBox", nil, scrollFrame)
	DaHudExportFrame.editBox = editBox
	scrollFrame:SetScrollChild(editBox)
	editBox:SetFontObject(ChatFontNormal)
	editBox:SetMultiLine(true)
	editBox:SetMaxLetters(99999)
	editBox:SetWidth(450)
	editBox:SetHeight(314)
	editBox:SetPoint("BOTTOM", 5, 0)
	editBox:SetJustifyH("LEFT")
	editBox:SetJustifyV("TOP")
	editBox:SetAutoFocus(false)
	editBox:SetScript("OnTextChanged", function(this)
		if this:GetText() ~= this.text then
			this:SetText(this.text)
		end
	
		local s = _G.DaHud_ExportFrameScrollFrameScrollBar
		_G.DaHud_ExportFrameScrollFrame:UpdateScrollChildRect()
		local _, m = s:GetMinMaxValues()
		if m > 0 and this.max ~= m then
			this.max = m
			s:SetValue(m)
		end
	end)
	editBox:SetScript("OnEscapePressed", function(this)
		this:ClearFocus()
	end)
	_G.DaHud_ExportFrameButton:SetScript("OnClick", function(this)
		DaHudExportFrame:Hide()
		return
	end)
	createDaHudExportFrame = nil
end

local function createDaHudImportFrame()
	DaHudImportFrame = CreateFrame("Frame", "DaHud_ImportFrame", UIParent, "DialogBoxFrame")

	DaHudImportFrame:SetWidth(500)
	DaHudImportFrame:SetHeight(400)
	DaHudImportFrame:SetPoint("CENTER")
	DaHudImportFrame:SetBackdrop({
		bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]], 
	    edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], 
	    tile = true, tileSize = 16, edgeSize = 16, 
	    insets = { left = 5, right = 5, top = 5, bottom = 5 }
	})
	DaHudImportFrame:SetBackdropColor(0,0,0,1)

	local text = DaHudImportFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
	DaHudImportFrame.text = text
	text:SetPoint("TOP", 0, -5)
	text:SetPoint("LEFT")
	
	local closeButton = CreateFrame("Button", "DaHud_ImportFrameCloseButton", DaHudImportFrame, "UIPanelCloseButton")
	closeButton:SetPoint("TOPRIGHT", 0, 0)
	closeButton:SetScript("OnClick", function()
		DaHudImportFrame:Hide()
	end)
	text:SetPoint("RIGHT", closeButton)
	
	local scrollFrame = CreateFrame("ScrollFrame", "DaHud_ImportFrameScrollFrame", DaHudImportFrame, "UIPanelScrollFrameTemplate")
	scrollFrame:SetToplevel(true)
	scrollFrame:SetPoint("TOP", -10, -30)
	scrollFrame:SetWidth(455)
	scrollFrame:SetHeight(330)

	local editBox = CreateFrame("EditBox", nil, scrollFrame)
	DaHudImportFrame.editBox = editBox
	scrollFrame:SetScrollChild(editBox)
	editBox:SetFontObject(ChatFontNormal)
	editBox:SetMultiLine(true)
	editBox:SetMaxLetters(99999)
	editBox:SetWidth(450)
	editBox:SetHeight(314)
	editBox:SetPoint("BOTTOM", 5, 0)
	editBox:SetJustifyH("LEFT")
	editBox:SetJustifyV("TOP")
	editBox:SetAutoFocus(false)
	editBox:SetScript("OnTextChanged", function(this)
		--if this:GetText() ~= this.text then
			--this:SetText(this.text)
		--end
	
		local s = _G.DaHud_ImportFrameScrollFrameScrollBar
		_G.DaHud_ImportFrameScrollFrame:UpdateScrollChildRect()
		local _, m = s:GetMinMaxValues()
		if m > 0 and this.max ~= m then
			this.max = m
			s:SetValue(m)
		end
	end)
	editBox:SetScript("OnEscapePressed", function(this)
		this:ClearFocus()
	end)
	_G.DaHud_ImportFrameButton:SetScript("OnClick", function(this)
		code = editBox:GetText()
		local code = assert(loadstring("return " .. code))()
		
		DaHud_Module_Layout:ImportLayout(code)
		
		DaHudImportFrame:Hide()
		return
	end)
	createDaHudImportFrame = nil
end

--- ========================================================= ---
---  Save Layout
--- ========================================================= ---
function DaHud_Module_Layout:ImportLayout(code)
	if not(code.Name) or not(code.Revision) then return end

	local data = {
		Name = code.Name,
		Revision = code.Revision,
		
		DaHud = {
			settings = {
			},
			colors = {
			},
		},
		
		Module_Bars = {
		},
		
		Module_Portrait = {
		},
		
		Module_Icons = {
		},
		
		Module_Text = {
		},
		
		Module_Model = {
		},
		
		Module_Buffs = {
		},
	}
	
	if code.DaHud.settings then
		data.DaHud.settings = code.DaHud.settings
	end
	if code.DaHud.colors then
		data.DaHud.colors = code.DaHud.colors
	end
	
	if code.Module_Bars then
		data.Module_Bars = code.Module_Bars
	end
	
	if code.Module_Portrait then
		data.Module_Portrait = code.Module_Portrait
	end
	
	if code.Module_Icons then
		data.Module_Icons = code.Module_Icons
	end
	
	if code.Module_Text then
		data.Module_Text = code.Module_Text
	end
	
	if code.Module_Model then
		data.Module_Model = code.Module_Model
	end
	
	if code.Module_Buffs then
		data.Module_Buffs = code.Module_Buffs
	end
	
	DaHud.db.account.customLayouts[code.Name] = data
	
	self:SetupOptions()
end

--- ========================================================= ---
---  Open Import Frame
--- ========================================================= ---
function DaHud_Module_Layout:OpenImportFrame()
	if createDaHudImportFrame then
		createDaHudImportFrame()
	end

	if not IsMacClient() then
		DaHudImportFrame.text:SetText(L["Import: Copy text from an external source and press Ctrl-V to paste."])
	else
		DaHudImportFrame.text:SetText(L["Import: Copy text from an external source and press Cmd-V to paste."])
	end
	
	local editBox = DaHudImportFrame.editBox
	editBox.text = nil
	editBox:SetText("")
	
	DaHudImportFrame:Show()
	editBox:SetFocus()
end

--- ========================================================= ---
---  Open Export Frame
--- ========================================================= ---
function DaHud_Module_Layout:OpenExportFrame(value)
	if createDaHudExportFrame then
		createDaHudExportFrame()
	end

	if not IsMacClient() then
		DaHudExportFrame.text:SetText(L["Export: Highlight All by pressing Ctrl-A, Copy Text by pressing Ctrl-C."])
	else
		DaHudExportFrame.text:SetText(L["Export:  Highlight All by pressing Cmd-A, Copy Text by pressing Cmd-C."])
	end
	
	local editBox = DaHudExportFrame.editBox
	editBox.text = toLiteralString(DaHud.db.account.customLayouts[value])
	editBox:SetText(editBox.text)
	
	DaHudExportFrame:Show()
	editBox:SetFocus()
end

--- ========================================================= ---
---  Save Layout
--- ========================================================= ---
function DaHud_Module_Layout:SaveLayout(value)
	local data = {
		Name = value,
		Revision = VERSION,
		
		DaHud = {
			settings = {
			},
			colors = {
			},
		},
		
		Module_Bars = DaHud.db.namespaces.Module_Bars.profile,
		Module_Portrait = DaHud.db.namespaces.Module_Portrait.profile,
		Module_Icons = DaHud.db.namespaces.Module_Icons.profile,
		Module_Text = DaHud.db.namespaces.Module_Text.profile,
		Module_Model = DaHud.db.namespaces.Module_Model.profile,
		Module_Buffs = DaHud.db.namespaces.Module_Buffs.profile,
	}
	
	data.DaHud.settings = DaHud.db.profile.settings
	data.DaHud.colors = DaHud.db.profile.colors
	
	DaHud.db.account.customLayouts[value] = data
	
	self:SetupOptions()
end

--- ========================================================= ---
---  Delete Layout
--- ========================================================= ---
function DaHud_Module_Layout:DeleteLayout(value)
	
	local validate = validateLayoutName(value)
	if not(validate) then 
		DEFAULT_CHAT_FRAME:AddMessage("Cannot Delete "..value.." because it is a MetaLayout!")
		return
	end

	DaHud.db.account.customLayouts[value] = nil
	
	self:SetupOptions()
end

--- ========================================================= ---
---  Apply Layout
--- ========================================================= ---
function DaHud_Module_Layout:ApplyLayout(value)
	local layout = DaHud.db.account.customLayouts[value]
	
	DaHud.db.profile.Name = layout.Name
	DaHud.db.profile.Revision = layout.Revision

	for k,v in pairs(layout.DaHud.settings) do
		DaHud.db.profile.settings[k] = v
	end
	for k,v in pairs(layout.DaHud.colors) do
		DaHud.db.profile.colors[k] = v
	end

	for k,v in pairs(layout.Module_Bars) do
		if k ~= "number" and DaHud.db.namespaces.Module_Bars.profile[k] then
			local tablenumber = table.getn(DaHud.db.namespaces.Module_Bars.profile.hudframe1)
			for i=1, tablenumber do
				if v[i] ~= nil then
					DaHud.db.namespaces.Module_Bars.profile[k][i] = v[i]
				end
			end
		else
			DaHud.db.namespaces.Module_Bars.profile[k] = v
		end
	end	

	for k,v in pairs(layout.Module_Portrait) do
		if k ~= "number" and DaHud.db.namespaces.Module_Portrait.profile[k] then
			local tablenumber = table.getn(DaHud.db.namespaces.Module_Portrait.profile.hudportrait1)
			for i=1, tablenumber do
				if v[i] ~= nil then
					DaHud.db.namespaces.Module_Portrait.profile[k][i] = v[i]
				end
			end
		else
			DaHud.db.namespaces.Module_Portrait.profile[k] = v
		end
	end	

	if layout.Module_Icons.numbers then
		for k,v in pairs(layout.Module_Icons.numbers) do
			DaHud.db.namespaces.Module_Icons.profile.numbers[k] = v
		end
	end
	if layout.Module_Icons.player then
		for k,v in pairs(layout.Module_Icons.player) do
			if k ~= "number" and DaHud.db.namespaces.Module_Icons.profile.player[k] then
				local tablenumber = table.getn(DaHud.db.namespaces.Module_Icons.profile.player.hudicon1)
				for i=1, tablenumber do
					if v[i] ~= nil then
						DaHud.db.namespaces.Module_Icons.profile.player[k][i] = v[i]
					end
				end
			else
				DaHud.db.namespaces.Module_Icons.profile.player[k] = v
			end
		end
	end
	if layout.Module_Icons.target then
		for k,v in pairs(layout.Module_Icons.target) do
			if k ~= "number" and DaHud.db.namespaces.Module_Icons.profile.target[k] then
				local tablenumber = table.getn(DaHud.db.namespaces.Module_Icons.profile.target.hudicon1)
				for i=1, tablenumber do
					if v[i] ~= nil then
						DaHud.db.namespaces.Module_Icons.profile.target[k][i] = v[i]
					end
				end
			else
				DaHud.db.namespaces.Module_Icons.profile.target[k] = v
			end
		end
	end
	if layout.Module_Icons.pet then
		for k,v in pairs(layout.Module_Icons.pet) do
			if k ~= "number" and DaHud.db.namespaces.Module_Icons.profile.pet[k] then
				local tablenumber = table.getn(DaHud.db.namespaces.Module_Icons.profile.pet.hudicon1)
				for i=1, tablenumber do
					if v[i] ~= nil then
						DaHud.db.namespaces.Module_Icons.profile.pet[k][i] = v[i]
					end
				end
			else
				DaHud.db.namespaces.Module_Icons.profile.pet[k] = v
			end
		end
	end
	if layout.Module_Icons.targettarget then
		for k,v in pairs(layout.Module_Icons.targettarget) do
			if k ~= "number" and DaHud.db.namespaces.Module_Icons.profile.targettarget[k] then
				local tablenumber = table.getn(DaHud.db.namespaces.Module_Icons.profile.targettarget.hudicon1)
				for i=1, tablenumber do
					if v[i] ~= nil then
						DaHud.db.namespaces.Module_Icons.profile.targettarget[k][i] = v[i]
					end
				end
			else
				DaHud.db.namespaces.Module_Icons.profile.targettarget[k] = v
			end
		end
	end
	if layout.Module_Icons.focus then
		for k,v in pairs(layout.Module_Icons.focus) do
			if k ~= "number" and DaHud.db.namespaces.Module_Icons.profile.focus[k] then
				local tablenumber = table.getn(DaHud.db.namespaces.Module_Icons.profile.focus.hudicon1)
				for i=1, tablenumber do
					if v[i] ~= nil then
						DaHud.db.namespaces.Module_Icons.profile.focus[k][i] = v[i]
					end
				end
			else
				DaHud.db.namespaces.Module_Icons.profile.focus[k] = v
			end
		end
	end
	
	for k,v in pairs(layout.Module_Text) do
		if k ~= "number" and DaHud.db.namespaces.Module_Text.profile[k] then
			local tablenumber = table.getn(DaHud.db.namespaces.Module_Text.profile.hudtext1)
			for i=1, tablenumber do
				if v[i] ~= nil then
					DaHud.db.namespaces.Module_Text.profile[k][i] = v[i]
				end
			end
		else
			DaHud.db.namespaces.Module_Text.profile[k] = v
		end
	end	

	for k,v in pairs(layout.Module_Model) do
		if k ~= "number" and DaHud.db.namespaces.Module_Model.profile[k] then
			local tablenumber = table.getn(DaHud.db.namespaces.Module_Model.profile.hudmodel1)
			for i=1, tablenumber do
				if v[i] ~= nil then
					DaHud.db.namespaces.Module_Model.profile[k][i] = v[i]
				end
			end
		else
			DaHud.db.namespaces.Module_Model.profile[k] = v
		end
	end	

	for k,v in pairs(layout.Module_Buffs) do
		if k ~= "number" and DaHud.db.namespaces.Module_Buffs.profile[k] then
			local tablenumber = table.getn(DaHud.db.namespaces.Module_Buffs.profile.hudbuffs1)
			for i=1, tablenumber do
				if v[i] ~= nil then
					DaHud.db.namespaces.Module_Buffs.profile[k][i] = v[i]
				end
			end
		else
			DaHud.db.namespaces.Module_Buffs.profile[k] = v
		end
	end	
	
	self:TriggerEvent("DaHud_ReloadAllFrames")
end